﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace Gype.GUI
{
    public class InputMessage
    {
        public Win32Native.WM Message { get; set; }
        public Win32Native.LPARAM lParam { get; set; }
        public Win32Native.WPARAM wParam { get; set; }
        public bool IsHandled { get; set; }
    }

    public class InputSystem
    {
        public InputSystem(Control inputControl)
        {
            subclassWindow(inputControl.Handle);
        }

        public InputSystem(IntPtr inputControl)
        {
            subclassWindow(inputControl);
        }

        public void detach()
        {
            Win32Native.SetWindowLongPtr(mInputHandle, Win32Native.WindowLongFlags.GWL_WNDPROC, mOldProcedure);
        }

        public void attach(IntPtr inputHandle)
        {
            mInputHandle = inputHandle;

            mOldProcedure = Win32Native.SetWindowLongPtr(inputHandle, Win32Native.WindowLongFlags.GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(mSubclassProcedure));
        }

        private void subclassWindow(IntPtr inputHandle)
        {
            if (inputHandle == IntPtr.Zero)
                throw new ArgumentException("Attempted to subclass a null window.");

            mInputHandle = inputHandle;

            mSubclassProcedure = SubclassWindowProcedure;
            mOldProcedure = Win32Native.SetWindowLongPtr(inputHandle, Win32Native.WindowLongFlags.GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(mSubclassProcedure));
        }

        private int SubclassWindowProcedure(IntPtr hWindow, Win32Native.WM uMessage, Win32Native.WPARAM wParam, Win32Native.LPARAM lParam)
        {
            InputMessage message = new InputMessage()
            {
                IsHandled = false,
                lParam = lParam,
                wParam = wParam,
                Message = uMessage
            };

            if (OnInputMessage != null)
                OnInputMessage(message);

            if (!message.IsHandled && mOldProcedure != IntPtr.Zero)
                return Win32Native.CallWindowProc(mOldProcedure, hWindow, uMessage, wParam, lParam);

            return Win32Native.DefWindowProc(hWindow, uMessage, wParam, lParam);
        }

        public delegate void InputMessageEventDlg(InputMessage message);

        public event InputMessageEventDlg OnInputMessage;

        IntPtr mInputHandle;
        IntPtr mOldProcedure;
        Win32Native.WindowProcedure mSubclassProcedure;
    }
}
